package com.extremelylargepackage.level;

import java.util.Collection;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import android.util.Log;

import com.extremelylargepackage.GameResources;
import com.extremelylargepackage.entity.ScrollingBackground;
import com.extremelylargepackage.entity.Enemy;
import com.extremelylargepackage.entity.Entity;

public class Wave implements LevelEvent {
	private static Wave DUMMY_WAVE = null;
	private Map<Integer, Enemy> _enemies;
	private String _name;
	private transient ScrollingBackground _background;

	private long _elapsed;
	private long _duration;
	private boolean _isDummy;

	private static final float[] lanes;

	//Static constructor. Pretty Awesome.
	static
	{
		lanes = new float[8];
		for(int i = 0; i < lanes.length; i++)
		{
			lanes[i] = ((float)i/8)*GameResources.SCREEN_WIDTH;
		}
	}
	
	public Wave() 
	{
		_isDummy = false;
		_enemies = new Hashtable<Integer, Enemy>();
	}

	/**
	 * Progresses the wave by the specified time. If the wave is "done" (all enemies are dead or 
	 * specified time has elapsed), progressWave returns true, otherwise it returns false.
	 * 
	 * @param time
	 * @return status of wave
	 */
	@Override
	public void updateState(long time) {
		_elapsed += time;
	}

	public static Wave parse(Element waveElem) throws MalformedLevelException
	{
		Wave wave = new Wave();

		wave._name = waveElem.getAttribute("name");

		String durationStr = waveElem.getAttribute("duration");
		if(durationStr.equals("")) {
			wave._duration = -1;
		} else {
			try {
				wave._duration = LevelParser.parseTimeValue(durationStr);
			} catch(IllegalArgumentException iae) {
				throw new MalformedLevelException("Illegal duration in wave \"" + wave._name + "\"", iae);
			}
		}

		NodeList nodes = waveElem.getChildNodes();
		for(int i = 0; i < nodes.getLength(); ++i) {
			Node n = nodes.item(i);
			if(n.getNodeType() == Node.ELEMENT_NODE) {
				Element elem = (Element)n;
				if(n.getNodeName().equals("enemy")) {
					String enemyType = elem.getAttribute("type");

					int lane;
					try {
						lane = Integer.parseInt(elem.getAttribute("lane"));
					} catch(NumberFormatException nfe) {
						throw new MalformedLevelException("Expected int value in wave \"" + wave._name + "\"");
					}
					Enemy enemy = GameResources.getEnemy(enemyType);
					enemy.setLocX(lanes[lane-1]);
					//So the enemy doesn't spawn on screen.
					enemy.setLocY(enemy.getHeight() * -1);
					//So the enemy flies into the game field.
					enemy.setDirY(.05f * GameResources.SCREEN_HEIGHT + enemy.getHeight());
					wave._enemies.put(lane, enemy);
				}
			}
		}

		return wave;
	}

	/**
	 * Returns an empty wave with a duration <= 0.
	 * @return
	 */
	public static Wave dummyWave() {
		if(DUMMY_WAVE == null) {
			DUMMY_WAVE = new Wave();
			DUMMY_WAVE._isDummy = true;
			DUMMY_WAVE._duration = Long.MIN_VALUE;
		}

		return DUMMY_WAVE;
	}

	@Override
	public Map<Integer, Enemy> getEnemies()
	{
		return _enemies;
	}

	@Override
	public boolean finished()
	{
		if(_duration > -1 && _elapsed > _duration)
			return true;

		for(Enemy e : _enemies.values()) {
			if(!e.finished())
				return false;
		}
		return true;
	}

	@Override
	public Collection<Entity> getScenery()
	{
		return Collections.emptyList();
	}
	
	public void setDuration(long d)
	{
		_duration = d;
	}
	
	public long getDuration()
	{
		return _duration;
	}
	
	public boolean isDummy()
	{
		return _isDummy;
	}
}
